package com.lucenten.collect.gnss.handler.tools.compute;


public class Martrix {
    //计算n阶行列式（N=n-1）
    public static double det(double[][] matrix, int n) {
        if (n < 0) {
            return 0;
        }
        if (n == 0) {
            return matrix[0][0];
        }
        if (n == 1) {
            return matrix[0][0] * matrix[1][1] - matrix[0][1] * matrix[1][0];
        }
        double num = 0;
        int cha = 0;
        double[][] b = new double[n][n];
        //T0循环
        for (int t0 = 0; t0 <= n; t0++) {
            //T1循环
            for (int t1 = 1; t1 <= n; t1++)  {
                //T2循环
                for (int t2 = 0; t2 <= n - 1; t2++) {
                    if (t2 == t0) {
                        cha = 1;
                    }
                    b[t1 - 1][t2] = matrix[t1][t2 + cha];
                }//T2循环
                cha = 0;
            }//T1循环
            num = num + matrix[0][t0] * det(b, n - 1) * Math.pow((-1), t0);
        }//T0循环
        return num;
    }
    /**
     * 求解逆矩阵
     *
     * @param data
     * @return
     */
    public static double[][] getInvMatrix(double[][] data) {
        // 1.求出行列式的模|data|
        double m = getHL(data);
        // 若行列式的值为0，则表明逆矩阵不存在
        if (DecimalUtil.compareTo(m, 0) == 0) {
            System.out.println("----------------行列式的模为0，逆矩阵不存在-----------------");
            return null;
        }
        // System.out.println("行列式:" + m);

        // 创建一个等容量的逆矩阵
        double[][] newData = new double[data.length][data.length];
        for (int i = 0; i < data.length; i++) {
            for (int j = 0; j < data.length; j++) {
                double num;
                if ((i + j) % 2 == 0) {
                    num = getHL(getDY(data, i + 1, j + 1));
                } else {
                    num = -getHL(getDY(data, i + 1, j + 1));
                }
                newData[i][j] = num / m;
            }
        }
        // 2.转置代数余子式
        newData = getA_T(newData);
        return newData;
    }

    /**
     * 求解行列式的模
     *
     * @param data
     * @return float
     */
    public static double getHL(double[][] data) {
        // 终止条件
        if (data.length == 2) {
            return data[0][0] * data[1][1] - data[0][1] * data[1][0];
        }

        if (data.length == 1) {
            return data[0][0];
        }

        double total = 0;
        // 根据data 得到行列式的行数和列数
        int num = data.length;
        // 创建一个大小为num 的数组存放对应的展开行中元素求的的值
        double[] nums = new double[num];

        for (int i = 0; i < num; i++) {
            if (i % 2 == 0) {
                nums[i] = data[0][i] * getHL(getDY(data, 1, i + 1));
            } else {
                nums[i] = -data[0][i] * getHL(getDY(data, 1, i + 1));
            }
        }

        for (int i = 0; i < num; i++) {
            total += nums[i];
        }

//     System.out.println("total=" + total);
        return total;
    }

    /**
     * 求解代数余子式
     *
     * @param data 原始矩阵
     * @param h    待求解元素的行
     * @param v    待求解元素的列
     * @return
     */
    public static double[][] getDY(double[][] data, int h, int v) {
        int H = data.length;
        int V = data[0].length;
        double[][] newData = new double[H - 1][V - 1];

        for (int i = 0; i < newData.length; i++) {
            if (i < h - 1) {
                for (int j = 0; j < newData[i].length; j++) {
                    if (j < v - 1) {
                        newData[i][j] = data[i][j];
                    } else {
                        newData[i][j] = data[i][j + 1];
                    }
                }
            } else {
                for (int j = 0; j < newData[i].length; j++) {
                    if (j < v - 1) {
                        newData[i][j] = data[i + 1][j];
                    } else {
                        newData[i][j] = data[i + 1][j + 1];
                    }
                }

            }
        }
        return newData;
    }

    /**
     * 取得转置矩阵
     *
     * @param A
     * @return float[][]
     */
    public static double[][] getA_T(double[][] A) {
        int h = A.length;
        int v = A[0].length;
        // 创建和A行和列相反的转置矩阵
        double[][] A_T = new double[v][h];
        // 根据A取得转置矩阵A_T
        for (int i = 0; i < h; i++) {
            for (int j = 0; j < v; j++) {
                A_T[j][i] = A[i][j];
            }
        }
        return A_T;
    }
}